<?php
// 允许跨域及OPTIONS请求，本地使用可以去掉
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE,OPTIONS,PATCH');
// 返回application/json
header('Content-Type:application/json; charset=utf-8');

// -------------------------------------
// 运行前请先设置好相关参数
// -------------------------------------
global $url, $merchantId, $publicKey, $privateKey;
$url = 'http://xxx/pay/v3.1/';
$merchantId = '00000000-0000-0000-0000-000000000000';
$publicKey = '';
$privateKey = '';
// -------------------------------------

$postStr = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
$post_arr = json_decode(strip_tags($postStr), true);
// 单文件处理，根据类型执行不同方法	
$method_type = isset($_GET['type']) ? $_GET['type'] : '';

// -------------------------------------
// 买币接口
// -------------------------------------
if ('payment/startToPay' == $method_type) {
	// 买单格式
	$preBuyBillData = array_merge(
		$post_arr, 
		array(
			'merchantId' => $merchantId,
			'merchantOrderCode' => "PHPBUY-" . getMillisecond(),
			'requestTimestamp' => getMillisecond(),
			'subject' => 'PHP测试商品'
		)
	);
	// 提交请求
	$ret_arr = PostData(packetPostData($preBuyBillData), 0);
	// 组装二次签名校验参数
	if(200 == $ret_arr['code']) {
		// 验签，自定义错误返回
		if (!verifyData($ret_arr['data'])) jsonReturn('666', '验证签名失败', '');
		
		unset($ret_arr['data']['merchantSign']);
		$billData = array(
			'billCode' => $ret_arr['data']['billCode'],
			'merchantId' => $merchantId,
			'requestTimestamp' => getMillisecond()
		);
		$ret_arr['data']['initToPayment'] = packetPostData($billData);
		jsonReturn(200, '', $ret_arr['data']);
	}
	jsonReturn($ret_arr['code'], $ret_arr['message'], '');
	
// -------------------------------------
// 卖币 STEP1 获取价格
// -------------------------------------
} else if ('sellCoin/queryMatchingTotalPrice' == $method_type) {
	// 请求卖单价格格式
	$preGetPriceData = array_merge(
		$arr_post,
		array(
			'merchantId' => $merchantId,
			'requestTimestamp' => getMillisecond()
		)
	);
	// 提交请求
	$ret_arr = PostData(packetPostData($preGetPriceData), 1);
	// 返回结果加工
	if (200 == $ret_arr['code']) {
		// 验签，自定义错误返回
		if (!verifyData($ret_arr['data'])) jsonReturn('666', '验证签名失败', '');
		jsonReturn(200, '', $ret_arr['data']);
	} 
	jsonReturn($ret_arr['code'], $ret_arr['message'], '');

// -------------------------------------
// 卖币 STEP2 下单
// -------------------------------------
} else if ('sellCoin/initialToSellCoin' == $method_type) {
	
	$merchantOrderCode = "PHPSELL-" . getMillisecond();
	// 下卖单格式
	$preSellBillData = array_merge(
		$arr_post,
		array(
			'merchantId' => $merchantId,
			'merchantOrderCode' => $merchantOrderCode,
			'currencyName' => 'CNY',
			'requestTimestamp' => getMillisecond()
		)
	);
	// 提交请求
	$ret_arr = PostData(packetPostData($preSellBillData), 2);
	// 返回结果加工
	if (200 == $ret_arr['code']) {
		// 验签，自定义错误返回
		if (!verifyData($ret_arr['data'])) jsonReturn('666', '验证签名失败', '');
		// 添加商家订单号
		$ret_arr['data']['merchantOrderCode'] = $merchantOrderCode;
		jsonReturn(200, '', $ret_arr['data']);
	} 
	jsonReturn($ret_arr['code'], $ret_arr['msg'], '');
	
// -------------------------------------
// 卖币 STEP3 放币
// -------------------------------------
} else if ('sellCoin/confirmedReceiptAndCoinRelease' == $method_type) {
	// TODO: 安全原因未实现，由后台处理
}

// -------------------------------------
// 提交数据方法，请根据项目需要更改
// -------------------------------------
function PostData($data_arr, $step)
{
	global $url, $merchantId, $privateKey;
	$data = json_encode($data_arr, JSON_UNESCAPED_SLASHES);
	switch($step)
	{
	case 0:
		$interface = 'createPrePaymentBill';	
		break;
	case 1:
		$interface = 'queryMatchingTotalPrice';	
		break;
	case 2:
		$interface = 'initialToSellCoin';	
		break;
	case 3:
		$interface = 'confirmedReceiptAndCoinRelease';	
		break;
	default:
		return array('code' => 404, 'message' => '无此接口');
	}
	// CURL提交请求
	$ch = curl_init($url. $interface);
	curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
	curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array(
		'Content-Type: application/json',
		'Content-Length: ' . strlen($data))
	);
	$result = json_decode(curl_exec($ch), true);
	return $result;
}

// -------------------------------------
// 通用方法，一般不需要修改
// -------------------------------------
function packetPostData($data_arr)
{
	global $privateKey;
	// 请求参数排序
	ksort($data_arr, SORT_STRING);
	// 生成请求字符串
	$queryStr = genQueryString($data_arr);
	// 生成签名
	$sign = getSign($queryStr, $privateKey);
	// 组装请求参数数组
	$postArr = array_merge($data_arr, array('merchantSign' => $sign));
	return $postArr;
}

// 校验签名
function verifyData($data_arr)
{
	global $publicKey;
	// 签名不存在，出错返回
	if(!isset($data_arr['merchantSign'])) return false;
	// 保存签名，去掉签名字段
	$sign = $data_arr['merchantSign'];
	unset($data_arr['merchantSign']);
	// 参数排序
	ksort($data_arr, SORT_STRING);
	// 生成待验签字符串
	$queryStr = genQueryString($data_arr);
	$ok = verifySign($queryStr, $sign, $publicKey);
	return $ok;
}

// -------------------------------------
// 工具方法，不要修改
// -------------------------------------
function genQueryString($data_arr)
{
	$queryStr = implode(',', array_map(function($v, $k) { return sprintf("%s=%s", $k, $v); }, $data_arr, array_keys($data_arr)));
	return $queryStr;
}

// 生成签名
function getSign($content, $privateKey)
{
	$key = openssl_get_privatekey($privateKey);
	openssl_private_encrypt($content, $sign, $privateKey);
	openssl_sign($content, $signature, $key, "SHA256");
	openssl_free_key($key);
	$sign = base64_encode($signature);
	return $sign;
}

// 验签
function verifySign($content, $sign, $publicKey)
{
    $key = openssl_get_publickey($publicKey);
    $ok = openssl_verify($content, base64_decode($sign), $key, 'SHA256');
    openssl_free_key($key);
    return $ok;
}

// JSON返回
function jsonReturn($code, $msg, $data)
{
	$ret = array('code' => $code);
	200 == $code ? $ret['data'] = $data : $ret['message'] = $msg;
	exit(json_encode($ret, JSON_UNESCAPED_SLASHES));
}

// 取微秒时间戳
function getMillisecond() { 
	list($t1, $t2) = explode(' ', microtime()); 
	return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000); 
}